package com.lonely.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lonely.common.core.domain.BaseEntity;
import com.lonely.common.core.domain.Select;
import com.lonely.system.domain.entity.SysRole;
import com.lonely.system.domain.entity.SysUser;
import com.lonely.common.core.page.Condition;
import com.lonely.common.enums.CommonStatus;
import com.lonely.common.utils.SecurityUtils;
import com.lonely.system.domain.entity.SysFactory;
import com.lonely.system.domain.entity.SysRoleMenu;
import com.lonely.system.domain.entity.SysUserRole;
import com.lonely.system.domain.dto.role.*;
import com.lonely.system.domain.dto.user.SysUserRoleNameDto;
import com.lonely.system.domain.vo.system.role.QueryToBeAllocatedUserInfoVo;
import com.lonely.system.domain.vo.system.role.SysRoleInfoVo;
import com.lonely.system.domain.vo.system.role.SysRolePageQueryVo;
import com.lonely.system.domain.vo.system.role.SysRoleUserInfoVo;
import com.lonely.system.mapper.SysRoleMapper;
import com.lonely.system.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 角色 业务层处理
 *
 * @author fzzf
 */
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {

    @Autowired
    private SysRoleMapper roleMapper;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private ISysFactoryService sysFactoryService;

    @Autowired
    private ISysUserRoleService sysUserRoleService;

    @Autowired
    private ISysRoleMenuService sysRoleMenuService;


    /**
     * 菜单分页查询列表
     *
     * @param queryDto
     * @return
     */
    @Override
    public Page<SysRolePageQueryVo> page(SysRolePageQueryDto queryDto) {
        Page<SysRole> page = Condition.page(queryDto);
        QueryWrapper<SysRole> queryWrapper = Condition.getQueryWrapper(BeanUtil.beanToMap(queryDto), SysRole.class);
        Page<SysRole> rolePage = super.page(page, queryWrapper);
        Page<SysRolePageQueryVo> resultPage = new Page<>();
        BeanUtils.copyProperties(rolePage, resultPage);
        if (CollUtil.isNotEmpty(rolePage.getRecords())) {
            resultPage.setRecords(rolePage.getRecords().stream().map(x -> {
                SysRolePageQueryVo sysRolePageQueryVo = new SysRolePageQueryVo();
                BeanUtils.copyProperties(x, sysRolePageQueryVo);

                // 填充信息
                sysRolePageQueryVo.setUpdateTime(DateUtil.formatDateTime(x.getUpdateTime()));
                sysRolePageQueryVo.setUpdateBy(this.sysUserService.getUserNameById(Convert.toLong(x.getUpdateBy())));

                return sysRolePageQueryVo;
            }).collect(Collectors.toList()));
        }

        return resultPage;
    }

    /**
     * 根据角色id获取角色信息
     *
     * @param roleId
     * @return
     */
    @Override
    public SysRoleInfoVo getRoleInfo(Long roleId) {
        SysRole sysRole = super.getById(roleId);
        Assert.notNull(sysRole, "角色不存在");

        // 查询角色id关联的菜单权限
        List<Long> menuIds = this.sysRoleMenuService.list(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId))
                .stream().filter(Objects::nonNull).map(SysRoleMenu::getMenuId).distinct().collect(Collectors.toList());

        SysRoleInfoVo sysRoleInfoVo = new SysRoleInfoVo();
        BeanUtils.copyProperties(sysRole, sysRoleInfoVo);
        sysRoleInfoVo.setMenuIds(menuIds);
        return sysRoleInfoVo;
    }

    /**
     * 创建角色
     *
     * @param submitDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(SysRoleSubmitDto submitDto) {
        Assert.isNull(submitDto.getId(), "参数错误(id)");
        this.checkRole(submitDto);

        // 创建角色
        SysRole sysRole = new SysRole();
        sysRole.setId(null);
        sysRole.setRoleName(submitDto.getRoleName());
        sysRole.setStatus(CommonStatus.ENABLE.code);
        sysRole.setCreateBy(SecurityUtils.getUserId());
        sysRole.setUpdateBy(SecurityUtils.getUserId());
        sysRole.setRemark(submitDto.getRemark());
        super.save(sysRole);

        // 创建角色菜单关联
        List<Long> allMenuIds = new ArrayList<>();
        allMenuIds.addAll(submitDto.getMenuIds());
        allMenuIds.addAll(submitDto.getButtonIds());
        this.sysRoleMenuService.batchSaveRoleMenus(sysRole.getId(), allMenuIds);
    }

    /**
     * 编辑角色
     *
     * @param submitDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(SysRoleSubmitDto submitDto) {
        Assert.notNull(submitDto.getId(), "参数错误(id)");
        this.checkRole(submitDto);

        // 更新角色信息
        SysRole oldRole = super.getById(submitDto.getId());
        oldRole.setRoleName(submitDto.getRoleName());
        oldRole.setRemark(submitDto.getRemark());
        oldRole.setUpdateBy(SecurityUtils.getUserId());
        super.updateById(oldRole);

        // 创建角色菜单关联
        List<Long> allMenuIds = new ArrayList<>();
        allMenuIds.addAll(submitDto.getMenuIds());
        allMenuIds.addAll(submitDto.getButtonIds());
        this.sysRoleMenuService.batchSaveRoleMenus(oldRole.getId(), allMenuIds);
    }

    /**
     * 校验角色信息
     *
     * @param submitDto
     */
    private void checkRole(SysRoleSubmitDto submitDto) {
        // 校验名称是否已存在
        int exists = super.count(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getRoleName, submitDto.getRoleName())
                .ne(submitDto.getId() != null, SysRole::getId, submitDto.getId())
        );
        Assert.isTrue(exists == 0, "角色名称已存在");

        // 校验角色id是否存在
        if (submitDto.getId() != null) {
            SysRole oldRole = super.getById(submitDto.getId());
            Assert.notNull(oldRole, "角色不存在");
            Assert.isTrue(Objects.equals(CommonStatus.ENABLE.code, oldRole.getStatus()), "该用户已停用");
        }
    }

    /**
     * 通过角色ID删除角色
     *
     * @param roleId 角色ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRoleById(Long roleId) {
        // 删除角色与菜单关联
        this.sysRoleMenuService.deleteByRoleId(roleId);

        // 删除角色和用户的关联

        // 删除角色信息
        super.removeById(roleId);
    }

    /**
     * 批量删除角色
     *
     * @param requestDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteByRoleIds(BatchDeleteRoleDto requestDto) {

        if (CollUtil.isEmpty(requestDto.getRoleIds())) {
            return;
        }

        // 删除角色与菜单关联
        this.sysRoleMenuService.batchDeleteByRoleIds(requestDto.getRoleIds());

        // 删除角色和用户的关联

        // 删除角色信息
        super.removeByIds(requestDto.getRoleIds());
    }

    /**
     * 新增角色分页查询列表
     *
     * @param queryDto
     * @return
     */
    @Override
    public Page<SysRolePageQueryVo> addRolePage(AddRolePageQueryDto queryDto) {

        // 获取选中的用户已绑定的角色id集合
        List<SysUserRole> userRoles = this.sysUserRoleService.list(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, queryDto.getUserId()));
        List<Long> excludeRoleIds = userRoles.stream().map(SysUserRole::getRoleId).distinct().collect(Collectors.toList());

        Page<SysRole> page = Condition.page(queryDto);
        LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<SysRole>().like(StrUtil.isNotBlank(queryDto.getRoleName()), SysRole::getRoleName, queryDto.getRoleName())
                .notIn(CollUtil.isNotEmpty(excludeRoleIds), SysRole::getId, excludeRoleIds)
                .eq(SysRole::getStatus, CommonStatus.ENABLE.code);
        Page<SysRole> rolePage = super.page(page, queryWrapper);
        Page<SysRolePageQueryVo> resultPage = new Page<>();
        BeanUtils.copyProperties(rolePage, resultPage);
        if (CollUtil.isNotEmpty(rolePage.getRecords())) {
            resultPage.setRecords(rolePage.getRecords().stream().map(x -> {
                SysRolePageQueryVo sysRolePageQueryVo = new SysRolePageQueryVo();
                BeanUtils.copyProperties(x, sysRolePageQueryVo);

                if (x.getAttribution() != null) {
                    SysFactory factory = this.sysFactoryService.getById(x.getAttribution());
                    if (factory != null) {
                        sysRolePageQueryVo.setAttributionName(factory.getName());
                    }
                }
                return sysRolePageQueryVo;
            }).collect(Collectors.toList()));
        }
        return resultPage;
    }

    /**
     * 获取角色下拉列表选项值
     *
     * @return
     */
    @Override
    public List<Select> getRoleSelectOptions() {
        return super.list().stream().map(x -> new Select().setLabel(x.getRoleName()).setValue(Convert.toStr(x.getId()))).collect(Collectors.toList());
    }

    /**
     * 获取角色分配的用户信息分页列表
     *
     * @param queryDto
     * @return
     */
    @Override
    public Page<SysRoleUserInfoVo> getRoleUserInfoPage(SysRoleUserPageQueryDto queryDto) {
        Page<SysRoleUserInfoVo> page = Condition.page(queryDto);

        Page<SysRoleUserInfoVo> resultPage = super.getBaseMapper().roleUserPage(page, queryDto);
        if (CollUtil.isNotEmpty(resultPage.getRecords())) {
            resultPage.setRecords(resultPage.getRecords().stream().peek(x -> {
                // 手机号脱敏操作
                x.setPhone(DesensitizedUtil.mobilePhone(x.getPhone()));
            }).collect(Collectors.toList()));
        }
        return resultPage;
    }

    /**
     * 获取指定角色待分配的用户信息分页列表
     *
     * @param queryDto
     * @return
     */
    @Override
    public Page<QueryToBeAllocatedUserInfoVo> getRoleToBeAllocatedUserInfoPage(QueryToBeAllocatedUserInfoDto queryDto) {
        // 获取指定角色id已绑定的用户id集合
        List<Long> userIds = this.sysUserRoleService.list(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, queryDto.getRoleId()))
                .stream().map(SysUserRole::getUserId).distinct().collect(Collectors.toList());

        // 查询用户信息
        Page<SysUser> page = new Page<>(Convert.toLong(queryDto.getCurrent(), 1L), Convert.toLong(queryDto.getSize(), 10L));
        Page<SysUser> userPage = this.sysUserService.page(page, new LambdaQueryWrapper<SysUser>().notIn(CollUtil.isNotEmpty(userIds), SysUser::getId, userIds)
                .like(StrUtil.isNotBlank(queryDto.getUserName()), SysUser::getUserName, queryDto.getUserName())
                .eq(StrUtil.isNotBlank(queryDto.getUserPhone()), SysUser::getPhone, queryDto.getUserPhone()));

        Page<QueryToBeAllocatedUserInfoVo> resultPage = new Page<>();
        BeanUtils.copyProperties(userPage, resultPage);

        if (CollUtil.isNotEmpty(userPage.getRecords())) {
            // 用户角色列表映射
            List<Long> toBeAllocatedUserIds = userPage.getRecords().stream().map(BaseEntity::getId).distinct().collect(Collectors.toList());
            Map<Long, String> userRoleNamesMap = Optional.ofNullable(this.sysUserRoleService.queryUserRoleNames(toBeAllocatedUserIds)).orElse(new ArrayList<>())
                    .stream().collect(Collectors.groupingBy(SysUserRoleNameDto::getUserId, Collectors.mapping(SysUserRoleNameDto::getRoleName, Collectors.joining("|"))));

            resultPage.setRecords(userPage.getRecords().stream().map(x -> {
                QueryToBeAllocatedUserInfoVo toBeAllocatedUserInfoVo = new QueryToBeAllocatedUserInfoVo();
                toBeAllocatedUserInfoVo.setId(x.getId());
                toBeAllocatedUserInfoVo.setName(x.getUserName());

                // 手机号脱敏操作
                toBeAllocatedUserInfoVo.setPhone(DesensitizedUtil.mobilePhone(x.getPhone()));

                // 设置角色信息
                toBeAllocatedUserInfoVo.setAssignedRoleNames(MapUtil.getStr(userRoleNamesMap, x.getId(), ""));

                return toBeAllocatedUserInfoVo;
            }).collect(Collectors.toList()));
        }
        return resultPage;
    }

    /**
     * 启用角色
     *
     * @param roleId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void enabled(Long roleId) {
        SysRole sysRole = super.getById(roleId);
        Assert.notNull(sysRole, "角色不存在");
        if (Objects.equals(sysRole.getStatus(), CommonStatus.DISABLE.code)) {
            sysRole.setStatus(CommonStatus.ENABLE.code);
            super.updateById(sysRole);
        }
    }

    /**
     * 停用角色
     *
     * @param roleId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void disabled(Long roleId) {
        SysRole sysRole = super.getById(roleId);
        Assert.notNull(sysRole, "角色不存在");
        if (Objects.equals(sysRole.getStatus(), CommonStatus.ENABLE.code)) {
            sysRole.setStatus(CommonStatus.DISABLE.code);
            super.updateById(sysRole);
        }
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限列表
     */
    @Override
    public Set<String> selectRolePermissionByUserId(Long userId) {
        List<SysRole> perms = roleMapper.selectRolePermissionByUserId(userId);
        Set<String> permsSet = new HashSet<>();
//        for (SysRole perm : perms) {
//            if (StringUtils.isNotNull(perm)) {
//                permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(",")));
//            }
//        }
        return permsSet;
    }



}
